package miaolib

import (
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli/v2"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

var lastIp string

type IPCheck struct {
}

func (s IPCheck) Command() *cli.Command {
	var comm = &cli.Command{
		Name:      "ip",
		Usage:     "获取公网IP",
		UsageText: "eg: miao ip -domain=uri -num=5  每秒获取一次公网ip，请求失败时允许重试5次 \n  ",
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:        "domain",
				Aliases:     []string{"d"},
				Usage:       "获取公网IP，默认通过 https://ipinfo.io/ip 获取",
				Value:       "https://ipinfo.io/ip",
				DefaultText: "https://ipinfo.io/ip",
			},
			&cli.IntFlag{
				Name:        "num",
				Aliases:     []string{"n"},
				Usage:       "允许网络重播的次数,1秒重新请求一次",
				Value:       5,
				DefaultText: "5",
			},
			&cli.StringFlag{
				Name:        "model",
				Aliases:     []string{"m"},
				Usage:       "是否为单次获取，可选 one-单次获取；cycle-循环持续获取",
				Value:       "cycle",
				DefaultText: "cycle",
			},
		},
	}
	comm.Action = func(ctx *cli.Context) error {
		var (
			ip   string
			rNum int
		)
		model := ctx.String("model")
		num := ctx.Int("num")
		domain := ctx.String("domain")
		switch model {
		case "one":
			ip, num = s.getInterIp(domain, num)
			if ip == "" {
				return cli.Exit(fmt.Sprintf("通过[%s]获取公网IP时发生错误", domain), 1)
			}
			info := IPInfo{
				Curr: ip,
				Num:  num,
			}
			bs, _ := json.Marshal(info)
			w := bufio.NewWriter(os.Stdout)
			w.WriteString(string(bs) + "\n")
			w.Flush()
			return nil
		case "cycle":
			ticker := time.NewTicker(time.Second)
			for range ticker.C {
				ip, rNum = s.getInterIp(domain, num)
				var info IPInfo
				if ip == "" {
					info = IPInfo{
						Last: lastIp,
						Curr: "x.x.x.x",
						Num:  rNum,
					}
					logrus.Debugf("采集信息失败： %+v", ip)
					bs, _ := json.Marshal(info)
					w := bufio.NewWriter(os.Stdout)
					w.WriteString(string(bs) + "\n")
					w.Flush()
				} else {
					if lastIp == "" {
						fmt.Println("第一次获取ip:" + ip)
						lastIp = ip
						continue
					}
					logrus.Debugf("采集信息： %+v", ip)
					if strings.ToLower(ip) != strings.ToLower(lastIp) {
						info := IPInfo{
							Last: lastIp,
							Curr: ip,
							Num:  rNum,
						}
						logrus.Debugf("发现ip变化： %+v", ip)
						bs, _ := json.Marshal(info)
						w := bufio.NewWriter(os.Stdout)
						w.WriteString(string(bs) + "\n")
						w.Flush()
						lastIp = ip
					}
				}
			}
			return nil
		default:
			return cli.Exit(fmt.Sprintf("未知的model参数：%s", model), 1)
		}
		return nil
	}
	return comm
}

// getInterIp 获取公网IP
func (s IPCheck) getInterIp(serUri string, num int) (ip string, index int) {
	var err error
	ticker := time.NewTicker(time.Second)
	for range ticker.C {
		index++
		if index > num {
			return
		}
		ip, err = s.getForipinfo(serUri)
		if err != nil {
			continue
		} else {
			return
		}
	}
	return
}

// getForipinfo 通过 ipinfo 获取IP
func (s IPCheck) getForipinfo(uri string) (ip string, err error) {
	resp, err := http.Get(uri)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	var bs []byte
	bs, err = io.ReadAll(resp.Body)
	if err != nil {
		return
	}
	ip = string(bs)
	return
}

// getForipinfoSysPorxy 通过 ipinfo 获取IP
func (s IPCheck) getForipinfoSysPorxy(uri string) (ip string, err error) {
	client := &http.Client{
		Transport: &http.Transport{
			// 使用 ProxyFromEnvironment 函数从系统环境变量中获取代理配置
			Proxy: http.ProxyFromEnvironment,
		},
	}
	// 创建一个HTTP请求
	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		return
	}
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	var bs []byte
	bs, err = io.ReadAll(resp.Body)
	if err != nil {
		return
	}
	ip = string(bs)
	return
}
